#include "main.h" // In diese Datei jetzt alle Includes schreiben
// #define DEBUG
// #define DEBUG_CAM

GLfloat LightPos1[] = { -50,30,100,1 };
GLfloat LightIntens[] = { 1.0,1.0,1.0};
GLfloat LightColor[]  = { 1,0,0 };

// Hilfsariable zum an und ausschalten der Texturen/des Schiffs/der Faesser/...
int textureOnOff = 1;
int schiffOnOff  = 1;
int faesserOnOff = 1;
int lightOnOff   = 0;
int kranAnimationOnOff = 0;
int kollisionOnOff = 1;
int halleOnOff=0;

// 'Geschwindigkeit' der Kamera-(hoch und runter)-Steuerung
double qe = 0.2;

/* 
 * Hilfsvariablen, die fuer die Skybox und das Flutlicht die richtige Liste
 * aufrufen wenn zwischen Tag- und Nachtmodus gewechselt wird.
 */
GLuint whichSkyBox;
GLuint whichFlutlicht;

unsigned int zaehler = 0;

// temporaere Test-Variablen:
// float flutX = -11.4;
// float flutY = 1.21;
// float flutZ = -25.8;

// Fuer das Wasser um die Zeit zu nehmen
Timer timer;

void draw_baumt5()
{
  glPushMatrix();
  glScalef(4,4,4);
  zeichneBaum(4);
  glPopMatrix();
}


void draw_baum_begrenzung()
{
 
      for(int i=0;i<15;i++)
        {
	  glTranslatef(10,0,0);
	  glCallList(dlTreeT5);
	}

}



// Hier alle Funktioen zum initialiesieren von 3D-Objekten reinschreiben
void init_geometry()
{
  init_boden();
  init_water();
  init_cargoShipVBO();
  init_segelboot();
  init_poller(); // initialisiere den Rotationskoerper
  init_container();
  init_steg();

  /*
   * Generiere Display-Listen fuer einzelne Objekte
   */
  cout << "\n";
  generate_displaylist(dlTreeT5,draw_baumt5);
  cout << "Baum DisplayList: " << dlTreeT5 << "\n";
  /*generate_displaylist(dlTreeT1,draw_baumt1);
  cout << "Baum DisplayList: " << dlTreeT1 << "\n";*/
  generate_displaylist(dlTreeZaun, draw_baum_begrenzung);
  cout << "Baum-Begrenzung DisplayList: " << dlTreeZaun << "\n";
//   generate_displaylist(dlShip,draw_cargo_ship);
//   cout << "Schiff DisplayList: " << dlShip << "\n";
  generate_displaylist(dlPoller, draw_poller);
  cout << "Poller DisplayList: " << dlPoller << "\n";


  generate_displaylist(dlStegPoller,draw_steg_poller);
  generate_displaylist(dlSteg,draw_steg);

  //Generiere eine DisplayList fuer die Pallete
  generate_displaylist(dlPallete,draw_palette);
  cout << "Palette DisplayList: " << dlPallete << "\n";
  //Generiere eine DisplayList fuer ein blaues Fass
  generate_displaylist(dlFassBlau,draw_fass_blau);
  cout << "Fass (blau) DisplayList: " << dlFassBlau << "\n";
  //Generiere eine DisplayList fuer ein rotes Fass
  generate_displaylist(dlFassRot,draw_fass_rot);
  cout << "Fass (rot) DisplayList: " << dlFassRot << "\n";
  //Generiere eine DisplayList fuer eine Pallete mit roten Faessern
  generate_displaylist(dlFaesserPallaeteRot,draw_faesser_pallete_rot);
  cout << "Palette rote Faesser DisplayList: " << dlFaesserPallaeteRot << "\n";
  //Generiere eine DisplayList fuer eine Pallete mit blauen Faessern
  generate_displaylist(dlFaesserPallaeteBlau,draw_faesser_pallete_blau);
  cout << "Palette blaue Faesser DisplayList: " << dlFaesserPallaeteBlau << "\n";
  //Generiere eine DisplayList fuer einen Palleten-Berg
  generate_displaylist(dlPalletenBergRot,draw_palleten_berg_rot);
  generate_displaylist(dlPalletenBergBlau,draw_palleten_berg_blau);
  //cout << "Palettenberg DisplayList: " << dlPalletenBerg << "\n";
  //Generiere eine DisplayList fuer den Boden
  generate_displaylist(dlBoden,draw_boden_display);
  cout << "Boden DisplayList: " << dlBoden << "\n";
  
   //Generiere eine DisplayList fuer die Halle
  generate_displaylist(dlhalle,draw_komplette_halle);
  cout << "Halle DisplayList: " << dlhalle << "\n";

  //Displaylist fuer Skybox-Tag
  generate_displaylist(dlSkyBoxTag,zeichneSkyboxTag);
  cout << "Skybox-Tag DisplayList: " << dlSkyBoxTag << "\n";
  //Displaylist fuer Skybox-Nacht
  generate_displaylist(dlSkyBoxNacht,zeichneSkyboxNacht);
  cout << "Skybox-Nacht DisplayList: " << dlSkyBoxNacht << "\n";

  //Display-Listen fuer den Kran erstellen
  generate_displaylist(dlKran01Schiene,zeichneSchiene);
  cout << "Kran01   DisplayList: " << dlKran01Schiene << "\n";
  generate_displaylist(dlKran02Rad,zeichneRad);
  cout << "Kran02   DisplayList: " << dlKran02Rad << "\n";
  generate_displaylist(dlKran03Radkappe,zeichneRadkappe);
  cout << "Kran03   DisplayList: " << dlKran03Radkappe << "\n";
  generate_displaylist(dlKran04Mittelteil,zeichneMittelteil);
  cout << "Kran04   DisplayList: " << dlKran04Mittelteil << "\n";
  generate_displaylist(dlKran05Oberteil,zeichneOberteil);
  cout << "Kran05.1 DisplayList: " << dlKran05Oberteil << "\n";
  generate_displaylist(dlKran05Arm,zeichneArm);
  cout << "Kran05.2 DisplayList: " << dlKran05Arm << "\n";
  generate_displaylist(dlKran05Hebel,zeichneHebel);
  cout << "Kran05.3 DisplayList: " << dlKran05Hebel << "\n";
  generate_displaylist(dlKran06Stopper,zeichneStopper);
  cout << "Kran06   DisplayList: " << dlKran06Stopper << "\n";
  generate_displaylist(dlKran07Hand,zeichneHand);
  cout << "Kran07.1 DisplayList: " << dlKran07Hand << "\n";
  generate_displaylist(dlKran07Finger,zeichneFinger);
  cout << "Kran07.2 DisplayList: " << dlKran07Finger << "\n";

  //Display-Listen fuer die Flutlichter erstellen
  generate_displaylist(dlFlutlichtTag,zeichneFlutlichtTag);
  cout << "Flutlicht-Tag DisplayList: " << dlFlutlichtTag << "\n";
  generate_displaylist(dlFlutlichtNacht,zeichneFlutlichtNacht);
  cout << "Flutlicht-Nacht DisplayList: " << dlFlutlichtNacht << "\n";
}



void init(void)
{
  glClearColor(0.0,0.0,0.0,1.0);
  /*
   * Schattierungsmodell: smooth Shading, Gouralt shading mit glShadeModel(GL_SMOOTH);
   * fliessende Uebergaenge, Interpolation zwischen Eckpunkten
   * 3 Schritte
   * 1. Zu Eckpunkt E werden Normalen n aller angrenzenden Polygone berechnet und interpoliert
   * 2. Zu Normale n wird Schattierungswert mittels eines Reflexionsmodells berechnet
   * 3. Bilineare Interpolation zur Berechnung der Schattierungswerte im Inneren des Polygons
   *
   */
  glShadeModel(GL_SMOOTH);
  /*
   * Verdeckte Flaechen entfernen mit glEnable(GL_DEPTH_TEST);
   * Z-Buffering (Depth Buffer, Tiefenpuffer)
   *
   * Tiefe: Distanz von Bild zu Objekt
   *
   * Wenn zweiter Bildpunkt an gleicher Stelle --> z-Werte werden verglichen.
   * Kleinerer z-Wert bleibt erhalten bzw. Farb/Grauwerte (Schattierungswert)
   * werden neu berechnet, wenn der neue z-Wert kleiner ist als der alte.
   *
   * Vorteil: Einfache Implementierung. Auch nach der Abbildung bleibt der
   * z-Buffer erhalten, so dass jederzeit neue Objekte in der alten Szene
   * dargestellt werden.
   * Nachteil: Zusaetzlicher Speicherplatz (bis zu 32 Bit pro Pixel), speichert Tiefe.
   */
  glEnable(GL_DEPTH_TEST);
  // Alpha Blending wird aktiviert. (ueberblenden, Transparenz!)
  glEnable(GL_BLEND);
  
  /* -------------------------------------------- Licht */
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);

//   glLightfv(GL_LIGHT4, GL_DIFFUSE,LightIntens);
//   glLightfv(GL_LIGHT4, GL_COLOR,LightColor);
//   glEnable(GL_LIGHT4);

  //LIGHT0, LIGHT5, LIGHT6 und LIGHT7 sind in Benutzung

  //Konstante Komponenten fuer LIGHT5 und LIGHT6 werden initialisiert
  glLightf(GL_LIGHT6, GL_SPOT_EXPONENT, 6.0);
  glLightf(GL_LIGHT6, GL_SPOT_CUTOFF, 42.0);
  glLightfv(GL_LIGHT6, GL_AMBIENT, mat_weisslich);
  glLightfv(GL_LIGHT6, GL_DIFFUSE, mat_weisslich);
  glLightfv(GL_LIGHT6, GL_SPECULAR, mat_weisslich);
  glLightf(GL_LIGHT6, GL_CONSTANT_ATTENUATION, 1.1);
  glLightf(GL_LIGHT5, GL_SPOT_EXPONENT, 6.0);
  glLightf(GL_LIGHT5, GL_SPOT_CUTOFF, 42.0);
  glLightfv(GL_LIGHT5, GL_AMBIENT, mat_weisslich);
  glLightfv(GL_LIGHT5, GL_DIFFUSE, mat_weisslich);
  glLightfv(GL_LIGHT5, GL_SPECULAR, mat_weisslich);
  glLightf(GL_LIGHT5, GL_CONSTANT_ATTENUATION, 1.1);

  // Laenge wird berechnet und jede Komponente wird dadurch dividiert.
  glEnable(GL_NORMALIZE);

  glColorMaterial(GL_FRONT, GL_DIFFUSE);
  glEnable(GL_COLOR_MATERIAL);

  init_geometry();
  timer.start();
  whichSkyBox = dlSkyBoxTag;
  whichFlutlicht = dlFlutlichtTag;
  //cout << "Zurueck im hauptprogramm.\n";
}

void display(void)
{
  GLfloat light_position[] = {50.0, -10.0, 20.0, 0.0};

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //gehoert quasi zu GL_DEPTH_TEST
  glLoadIdentity();

  // Kamera-Standpunkt, -Bewegung usw.
  gluLookAt(kameraStandpunktX, kameraStandpunktY, kameraStandpunktZ,
		kameraLookAtX, kameraLookAtY, kameraLookAtZ,
		0.0, 1.0, 0.0);
  // Kamera-Standpunkt : variabel
  // schaut auf Punkt  : variabel
  // up-Vektor (zeigt nach oben) : 0,1,0


  // Drehung der Objekte um die jeweilige Achse (wird eigentlich nicht gebraucht)
  glRotatef(spinZ, 0.0, 0.0, 1.0); // (Spin, Achse(x,y,z))
  glRotatef(spinY, 0.0, 1.0, 0.0); // (Spin, Achse(x,y,z))
  glRotatef(spinX, 1.0, 0.0, 0.0); // (Spin, Achse(x,y,z))


   // Texturen initialisieren bzw. anschalten
   if(textureOnOff == 1) glEnable(GL_TEXTURE_2D);

   glPushMatrix();
   glLightfv(GL_LIGHT0, GL_POSITION, light_position);
//    glLightfv(GL_LIGHT4, GL_POSITION,LightPos1);


  glEnable(GL_CULL_FACE);
  //Zeit nehmen
   timeval startCount, endCount;
   gettimeofday(&startCount,NULL);

   // Fuer die Skybox muss das alles kurzfristig ausgeschaltet werden...
   glDisable(GL_LIGHTING);
   glDisable(GL_BLEND);
   glDisable(GL_DEPTH_TEST);

   #ifdef DEBUG
   cout << "Male Skybox.\n";
   #endif

   //------------------------Zeichne die Skybox
   glPushMatrix();
   glScalef(6.0,6.0,6.0);
   glCallList(whichSkyBox);
   glPopMatrix();

   // ...und wird hier wieder eingeschaltet
   glEnable(GL_DEPTH_TEST);
   glEnable(GL_BLEND);
   glEnable(GL_LIGHTING);


  /* glPushMatrix();
  glTranslatef(50.0, 6.1, 140.0);
  glRotatef(90, 0.0, 1.0, 0.0);
  glCallList(dlSteg);
  glPopMatrix();*/


  //----------------------- Zeichne die Flutlichtmasten

  glPushMatrix(); //fuer den Steg
	glTranslatef(90.0, 6.1, 140.0);
	glRotatef(227, 0.0, 1.0, 0.0);
	#ifdef DEBUG
	cout << "Male 1. Flutlicht\n";
	#endif
	glCallList(whichFlutlicht);
	GLfloat lightFlut1_spot_direction[] = {1.0,-1.0, 0.0,};
	GLfloat lightFlut1_position[] = {0.2,5.5,0.0, 1.0};
	glLightfv(GL_LIGHT6, GL_POSITION, lightFlut1_position);
	glLightfv(GL_LIGHT6, GL_SPOT_DIRECTION, lightFlut1_spot_direction);
  glPopMatrix();
  glPushMatrix(); //der andere...
	glTranslatef(80.0, 6.1, 30.0);
	glRotatef(200, 0.0, 1.0, 0.0);
	#ifdef DEBUG
	cout << "Male 2. Flutlicht\n";
	#endif
	glCallList(whichFlutlicht);
	GLfloat lightFlut2_spot_direction[] = {1.0,-1.0, 0.0,};
	GLfloat lightFlut2_position[] = {0.2,5.5,0.0, 1.0};
	glLightfv(GL_LIGHT5, GL_POSITION, lightFlut2_position);
	glLightfv(GL_LIGHT5, GL_SPOT_DIRECTION, lightFlut2_spot_direction);
  glPopMatrix();


  // ------------------------ Zeichne den Kran
  glPushMatrix();
  glScalef(1.5, 1.5, 1.5);
  glTranslatef(7.0,0.3,-0.0);
  #ifdef DEBUG
  cout << "Male Kran.\n";
  #endif
  zeichneKomplettenKran();
  glPopMatrix();

  // ------------------------ Zeichne ein paar Container
  glPushMatrix();
    glTranslatef(27.0,-0.1,39.0);
    glRotatef(-90, 1.0,0.0,0.0);
    glRotatef(82, 0.0,0.0,1.0);
    glScalef(0.75,0.75,0.75);
    draw_container(conAmerica,conAmerica_back);
    glTranslatef(-22.0,0.0,0.0);
    glRotatef(12, 0.0,0.0,1.0);
    draw_container(conIndia_back,conIndia);
  glPopMatrix();

   // ----------------------------- Zeichne halle
   if(halleOnOff) {
     glPushMatrix();
     glCallList(dlhalle);
     glPopMatrix();
   }


  // ------------------------Zeichne den Rotationskoerper
  glCullFace(GL_FRONT);
  glPushMatrix();
  glScalef(0.75,0.75,0.75);
  glTranslatef(2.0,0.0,3.0);
  #ifdef DEBUG
  cout << "Male Poller.\n";
  #endif
  glCallList(dlPoller);
  for(int i=0; i<7; i++) {
    glTranslatef(0.0,0.0,28.0);
    glCallList(dlPoller);
  }
  for(int i=0; i<6; i++) {
    glTranslatef(28.0,0.0,0.0);
    glCallList(dlPoller);
  }
  glPopMatrix();

   // ------------------------- Male den Steg
   glPushMatrix();
   glTranslatef(80,0.0,151.25);
   glRotatef(-180,0,1,0);
   #ifdef DEBUG
   cout << "Male Steg.\n";
   #endif
   glCallList(dlSteg);
   glPopMatrix();

   //---------------------- Zeichne Boden
   glPushMatrix();
   #ifdef DEBUG
   cout << "Male Boden.\n";
   #endif
   glCallList(dlBoden);
   glPopMatrix();

  glCullFace(GL_BACK);

  //----------------------Zeichne eine Pallete mit Faessern
  if(faesserOnOff)
    {
      glPushMatrix();
      glCallList(dlPalletenBergRot);
      glCallList(dlPalletenBergBlau);
      glPopMatrix();
    }


  // ----------------------Zeichne ein Schiff
  if(schiffOnOff)
    {
      glPushMatrix();
      glTranslatef(-16,-6,70);
      glRotatef(90,0,1,0);
      glScalef(0.2,0.2,0.2);
      draw_cargo_ship_vbo();
      //draw_segelboot();
      glPopMatrix();
      glPushMatrix();
        glTranslatef(-18.0,3.5,60.0);
        glRotatef(-90, 1.0,0.0,0.0);
        glRotatef(80, 0.0,0.0,1.0);
        glScalef(0.75,0.75,0.75);
        draw_container(conAfrica,conAfrica_back);
      glPopMatrix();
    }
  glDisable(GL_TEXTURE_2D);
  glDisable(GL_CULL_FACE);

  //----------------------------Male das kleine Segelboot 
  glPushMatrix();
  if(!lightOnOff)
    {
      glTranslatef(-60,-4.5,260);
      glRotatef(-45,0,1,0);
    }
  else
    {
      glTranslatef(62,-5.0,198);
      glRotatef(-180,0,1,0);
    }
  draw_segelboot();
  glPopMatrix();
  

  //---------------------- Male zwei Reihen von Baeumen
  glPushMatrix();
  glTranslatef(0,0,0);
  glCallList(dlTreeZaun);
  glRotatef(-90,0,1,0);
  glCallList(dlTreeZaun);
  glPopMatrix();
  

  //----------------------- Zeichne Wasser
  gettimeofday(&endCount,NULL);
  glPushMatrix();
  glTranslatef(-201,-3,0);
  draw_water((float)timer.getElapsedTime());
  glPopMatrix();




  glPopMatrix();
  //  glutPostRedisplay();

  glutSwapBuffers();
 
}


void reshape(int w, int h)
{
  glViewport(0,0, (GLsizei)w, (GLsizei)h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(60.0,(GLfloat)w/(GLfloat)h,1.0,800.0);
  glMatrixMode(GL_MODELVIEW);
 
}

void animate() {
	if(kranAnimationOnOff == 1) {
		if(container == 0) {
			if(radBewegung < -66.59 && radBewegung > -66.91) {
			radBewegung = -66.74;
			  if(oberteilRotate == 90.0) {
			    if(armBeweg == 27.5) {
			      if(handHochRunter < -13.3) {
				if(fingerAufZu < 1.7) {
					container = 1; // 1. Ziel erreicht (Container gefasst!)
				}
				else fingerAufZu -= 0.1;
			      }
			     	else handHochRunter -= 0.4; 
			    }
			    else if(armBeweg > 27.5) {
			      armBeweg -= 0.5;
			      hebelBeweg -= 0.015;
			    }
			    else {
			      armBeweg += 0.5;
			      hebelBeweg += 0.015;
			    }
			  }
			  else if(oberteilRotate > 90.0) oberteilRotate -= 1.5;
			  else oberteilRotate += 1.5;
			}
			else if(radBewegung < -66.59) radBewegung += 0.3;
			else if(radBewegung > -66.91) radBewegung -= 0.3;
		}
		else if(container == 1 || container == 2) {
			float radBewegDiff = 15.0;
			if(handHochRunter > -2.0 || container == 2) {
			  if(armBeweg == 25.0) {
			    if(radBewegung < (-66.59+radBewegDiff) && radBewegung > (-66.91+radBewegDiff)) {
			    radBewegung = (-66.74 + radBewegDiff);
			      if(oberteilRotate == 270.0) {
				container = 2;
				if(handHochRunter < -11.0) {
				  if(fingerAufZu >= 2.0) {
				    container = 3; // 2. Ziel erreicht (Container abstellbereit!)
				  }
				  else fingerAufZu += 0.1;
				}
				else handHochRunter -= 0.4;
			      }
			      else if(oberteilRotate > 270.0) oberteilRotate -= 1.5;
			      else oberteilRotate += 1.5;
			    }
			    else if(radBewegung < (-66.59+radBewegDiff)) radBewegung += 0.3;
			    else if(radBewegung > (-66.91+radBewegDiff)) radBewegung -= 0.3;
			  }
			  else if(armBeweg > 25.0) {
			    armBeweg -= 0.5;
			    hebelBeweg -= 0.015;
			  }
			  else {
			    armBeweg += 0.5;
			    hebelBeweg += 0.015;
			  }
			}
			else handHochRunter += 0.4;
		}
		else if(container == 3) {
			if(handHochRunter > -4.0) {
				container = 4; //3. Ziel erreicht, Container fertig abgestellt.
				kranAnimationOnOff = 0;
			}
			else handHochRunter += 0.4;
		}
	}
	glutPostRedisplay();
}

/* ARGSUSED1 */
void keyboard (unsigned char key, int x, int y) {
	float asdf = 0.01;
	int bla = 0;
	switch(key) {
		// temporaere Hilfsvariablen zum Veraendern von Werten
	case 'x':
		spinX += 3 % 360;
// 		flutX += asdf;
		glutPostRedisplay();
		break;
	case 'X':
		spinX -= 3 % 360;
// 		flutX -= asdf;
		glutPostRedisplay();
		break;
	case 'y':
		spinY += 3 % 360;
// 		flutY += asdf;
		glutPostRedisplay();
		break;
	case 'Y':
		spinY -= 3 % 360;
// 		flutY -= asdf;
		glutPostRedisplay();
		break;
	case 'z':
		spinZ += 3 % 360;
// 		flutZ += asdf;
		glutPostRedisplay();
		break;
	case 'Z':
		spinZ -= 3 % 360;
// 		flutZ -= asdf;
		glutPostRedisplay();
		break;
		// 'WASD'-Steuerung ----------------------
	case 'w':
		kameraStandpunktZ += vektorBewegungWS[1];
		kameraLookAtZ += vektorBewegungWS[1];
		lookAtVerschiebungZ += vektorBewegungWS[1];
		kameraStandpunktX += vektorBewegungWS[0];
		kameraLookAtX += vektorBewegungWS[0];
		lookAtVerschiebungX += vektorBewegungWS[0];
		if(kollisionOnOff == 1) {
			ueberpruefungAufSteg(); //Wird der Steg als Standpunkt angepeilt?
			if(kollisionsAbfrageX() == 1) {
				bla += 1;
			}
			else {
				kameraStandpunktX -= vektorBewegungWS[0];
				kameraLookAtX -= vektorBewegungWS[0];
				lookAtVerschiebungX -= vektorBewegungWS[0];
			}
			if(kollisionsAbfrageZ() == 1) {
				bla += 1;
			}
			else {
				kameraStandpunktZ -= vektorBewegungWS[1];
				kameraLookAtZ -= vektorBewegungWS[1];
				lookAtVerschiebungZ -= vektorBewegungWS[1];
			}
			if(bla > 0) glutPostRedisplay();
		}
		else glutPostRedisplay();
		#ifdef DEBUG_CAM
		printf("kameraStandpunktX: %f\n", kameraStandpunktX);
		printf("kameraStandpunktZ: %f\n\n", kameraStandpunktZ);
		#endif
		break;
	case 's':
		kameraStandpunktZ -= vektorBewegungWS[1];
		kameraLookAtZ -= vektorBewegungWS[1];
		lookAtVerschiebungZ -= vektorBewegungWS[1];
		kameraStandpunktX -= vektorBewegungWS[0];
		kameraLookAtX -= vektorBewegungWS[0];
		lookAtVerschiebungX -= vektorBewegungWS[0];
		if(kollisionOnOff == 1) {
			ueberpruefungAufSteg();
			if(kollisionsAbfrageX() == 1) {
				bla += 1;
			}
			else {
				kameraStandpunktX += vektorBewegungWS[0];
				kameraLookAtX += vektorBewegungWS[0];
				lookAtVerschiebungX += vektorBewegungWS[0];
			}
			if(kollisionsAbfrageZ() == 1) {
				bla += 1;
			}
			else {
				kameraStandpunktZ += vektorBewegungWS[1];
				kameraLookAtZ += vektorBewegungWS[1];
				lookAtVerschiebungZ += vektorBewegungWS[1];
			}
			if(bla > 0) glutPostRedisplay();
		}
		else glutPostRedisplay();
		#ifdef DEBUG_CAM
		printf("kameraStandpunktX: %f\n", kameraStandpunktX);
		printf("kameraStandpunktZ: %f\n\n", kameraStandpunktZ);
		#endif
		break;
	case 'd':
		kameraStandpunktZ += vektorBewegungAD[1];
		kameraLookAtZ += vektorBewegungAD[1];
		lookAtVerschiebungZ += vektorBewegungAD[1];
		kameraStandpunktX += vektorBewegungAD[0];
		kameraLookAtX += vektorBewegungAD[0];
		lookAtVerschiebungX += vektorBewegungAD[0];
		if(kollisionOnOff == 1) {
			ueberpruefungAufSteg();
			if(kollisionsAbfrageX() == 1) {
				bla += 1;
			}
			else {
				kameraStandpunktX -= vektorBewegungAD[0];
				kameraLookAtX -= vektorBewegungAD[0];
				lookAtVerschiebungX -= vektorBewegungAD[0];
			}
			if(kollisionsAbfrageZ() == 1) {
				bla += 1;
			}
			else {
				kameraStandpunktZ -= vektorBewegungAD[1];
				kameraLookAtZ -= vektorBewegungAD[1];
				lookAtVerschiebungZ -= vektorBewegungAD[1];
			}
			if(bla > 0) glutPostRedisplay();
		}
		else glutPostRedisplay();
		#ifdef DEBUG_CAM
		printf("kameraStandpunktX: %f\n", kameraStandpunktX);
		printf("kameraStandpunktZ: %f\n\n", kameraStandpunktZ);
		#endif
		break;
	case 'a':
		kameraStandpunktZ -= vektorBewegungAD[1];
		kameraLookAtZ -= vektorBewegungAD[1];
		lookAtVerschiebungZ -= vektorBewegungAD[1];
		kameraStandpunktX -= vektorBewegungAD[0];
		kameraLookAtX -= vektorBewegungAD[0];
		lookAtVerschiebungX -= vektorBewegungAD[0];
		if(kollisionOnOff == 1) {
			ueberpruefungAufSteg();
			if(kollisionsAbfrageX() == 1) {
				bla += 1;
			}
			else {
				kameraStandpunktX += vektorBewegungAD[0];
				kameraLookAtX += vektorBewegungAD[0];
				lookAtVerschiebungX += vektorBewegungAD[0];
			}
			if(kollisionsAbfrageZ() == 1) {
				bla += 1;
			}
			else {
				kameraStandpunktZ += vektorBewegungAD[1];
				kameraLookAtZ += vektorBewegungAD[1];
				lookAtVerschiebungZ += vektorBewegungAD[1];
			}
			if(bla > 0) glutPostRedisplay();
		}
		else glutPostRedisplay();
		#ifdef DEBUG_CAM
		printf("kameraStandpunktX: %f\n", kameraStandpunktX);
		printf("kameraStandpunktZ: %f\n\n", kameraStandpunktZ);
		#endif
		break;
	case 'q':
		kameraStandpunktY += qe;
		kameraLookAtY += qe;
		glutPostRedisplay();
		break;
	case 'e':
		kameraStandpunktY -= qe;
		kameraLookAtY -= qe;
		glutPostRedisplay();
		break;
		// Rad drehen -------------------------
	case '4':
		if(radBewegung >= -28.6) ;
		else {
			radBewegung += radBewegungTempo;
			radRotate += 3 % 360;
			glutPostRedisplay();
		}
		break;
	case '6':
		if(radBewegung <=-77.3) ;
		else {
			radRotate -= 3 % 360;
			radBewegung -= radBewegungTempo;
			glutPostRedisplay();
		}
		break;
		// Oberteil drehen --------------------
	case '8':
		if(fabs(oberteilRotate) != 360.0) {
			oberteilRotate += 3.0;
		} else oberteilRotate = 3.0;
		glutPostRedisplay();
		break;
	case '2':
		if(fabs(oberteilRotate) != 360.0) {
			oberteilRotate -= 3.0;
		} else oberteilRotate = -3.0;
		glutPostRedisplay();
		break;
		// Kran-Arm bewegen -------------------
	case '7':
		if(!(armBeweg >= 55.0)) {
			armBeweg += 0.5;
			hebelBeweg += 0.015;
			glutPostRedisplay();
			break;
		}
		break;
	case '9':
		if(armBeweg <= 25.0);
		else {
			armBeweg -= 0.5;
			hebelBeweg -= 0.015;
			glutPostRedisplay();
			break;
		}
		break;
	case '1':
		if(handHochRunter > -13.3) {
			handHochRunter -= 0.1;
			glutPostRedisplay();
		}
		break;
	case '3':
		if(handHochRunter < 0.5) {
			handHochRunter += 0.1;
			glutPostRedisplay();
		}
		break;
	case '0':
		if(fingerAufZu > 1.6) {
			fingerAufZu -= 0.01;
			glutPostRedisplay();
		}
		break;
	case ',':
		if(fingerAufZu < 2.0) {
			fingerAufZu += 0.01;
			glutPostRedisplay();
		}
		break;
	//Texturen an und ausschalten
	case 't':
		if(textureOnOff == 1) textureOnOff = 0;
		else textureOnOff = 1;
		glutPostRedisplay();
		break;
	//Kollisionsabfrage an und ausschalten
	case 'k':
		if(kollisionOnOff == 1) kollisionOnOff = 0;
		else kollisionOnOff = 1;
		glutPostRedisplay();
		break;
	//Schiff ein- und ausblenden
	case 'm':
		if(schiffOnOff == 1) schiffOnOff = 0;
		else schiffOnOff = 1;
		glutPostRedisplay();
		break;
	//Faesser ein- und ausblenden
	case 'n':
		if(faesserOnOff == 1) faesserOnOff = 0;
		else faesserOnOff = 1;
		glutPostRedisplay();
		break;
	//Licht an und ausschalten bzw. umschalten
	case 'l':
		if(lightOnOff == 0) {
			glDisable(GL_LIGHT0);
			glEnable(GL_LIGHT7);extern int lightOnOff; //Zwischen Tag und Nacht wechseln
			glEnable(GL_LIGHT6);
			glEnable(GL_LIGHT5);
			lightOnOff = 1;
			lsr=lampenaus;
			whichSkyBox=dlSkyBoxNacht;
			whichFlutlicht=dlFlutlichtNacht;
		}
		else {
			glEnable(GL_LIGHT0);
			glDisable(GL_LIGHT7);
			glDisable(GL_LIGHT6);
			glDisable(GL_LIGHT5);
			lightOnOff = 0;
			lsr=lampenaus;
			whichSkyBox=dlSkyBoxTag;
			whichFlutlicht=dlFlutlichtTag;
		}
		glutPostRedisplay();
		break;
	case '5':
		if(container != 4) {
			if(kranAnimationOnOff == 1) kranAnimationOnOff = 0;
			else kranAnimationOnOff = 1;
			glutPostRedisplay();
		}
		break;
		// Hilfsparameter --------------------
	case 'h':
		hilf += 1.0;
		glutPostRedisplay();
		break;
	case 'H':
		hilf -= 1.0;
		glutPostRedisplay();
		break;
	case '+':
		radBewegungTempo = 0.3;
		break;
	case '-':
		if(radBewegungTempo >=0.0) radBewegungTempo = 0.03;
		break;
	case 'i':
		if(torbewegung >-46) torbewegung = torbewegung-1;
		glutPostRedisplay();
		break;
	case 'I':
		if(torbewegung <0) torbewegung = torbewegung+1;
		glutPostRedisplay();
		break;
        case 'p':
		if(halleOnOff == 1) halleOnOff = 0;
		else halleOnOff = 1;
		glutPostRedisplay();
		break;
	case 27:
	
		exit(0);
		break;
	default:
		break;
	}
}

int main(int argc, char** argv)
{
  atexit(clearMemory);
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize(1280,800);
  glutInitWindowPosition(100,100);
  glutCreateWindow(argv[0]);
  init();
  glutDisplayFunc(display);
  glutReshapeFunc(reshape);
  glutKeyboardFunc(keyboard); //Tastatur
  glutMotionFunc(mausKamera); //Maus
  glutIdleFunc(animate);
  glutMainLoop();
  return 0;
}
